//
// class Agent - the class that represents the AI agent 
//
package classes;

import java.util.Vector;

public class Agent {
	
  private World wumpusWorld;
	private int size = 0;
	private int xLocation = 0;
	private int yLocation = 0;
	private boolean hasGold = false;

	public boolean knowsExitLocation = false;
	
	public AgentExploringWorld agentWorld;
	
	public Agent(World world) {
		
		agentWorld = new AgentExploringWorld(this);
		
		wumpusWorld = world;
		size = wumpusWorld.sizeOfWorld();
		xLocation = wumpusWorld.getAgentLocation().getX();
		yLocation = wumpusWorld.getAgentLocation().getY();
	}
	
	// method called by the WorldCreation class to tell the agent to decide the next move
  public Point nextMove() {
    char direction = ' ';
    
    // get current location from world, just in case a bat moved us
    xLocation = wumpusWorld.getAgentLocation().getX();
    yLocation = wumpusWorld.getAgentLocation().getY();
    
	  // we get the percepts and objects from the current cell
    int [] perceptArray = wumpusWorld.getPercepts();
	  char [] objectArray = wumpusWorld.getObjects();

    agentWorld.setPerceptsAndObjects(new Point(xLocation, yLocation), 
        perceptArray, objectArray);
	  
    if (!agentWorld.agentWorld[xLocation][yLocation].isBat) {
      // lowRisk policy movement for the agent
      Vector<AgentExploringCell> v =
        agentWorld.getVisitedIsland(null, agentWorld.agentWorld[xLocation][yLocation]);
      v = agentWorld.getUnvisitedBorder(v);
      v = agentWorld.getLowestRisk(v);
    
      // if we get several of them, choose the one closest to Gold/Exit
      Vector <AgentExploringCell> targetCells = agentWorld.highTargetProb(hasGold);
      v = agentWorld.getClosestPath(v, targetCells);
      AgentExploringCell c = getClosest(v);
      direction = agentWorld.getVisitedWay(agentWorld.agentWorld[xLocation][yLocation],c);
    
	    // printProbMap();
    }

		switch (direction)
		{
		  case 'E': return moveEast();
		  case 'N': return moveNorth();
		  case 'S': return moveSouth();
		  case 'W': return moveWest();
		  default: return new Point(xLocation, yLocation);
		}
	}
  
  private AgentExploringCell getClosest (Vector<AgentExploringCell> v) {
    AgentExploringCell agentCell = agentWorld.agentWorld[xLocation][yLocation];
    AgentExploringCell result = null;
    int dist = Integer.MAX_VALUE;
    
    for (int i=0; i<v.size(); i++) {
      int d = agentWorld.getDistance(agentCell,v.get(i));
      if (d<dist) {
        result = v.get(i);
        dist = d;
      }
    }
    
    return result;
  }

	public Point moveNorth() {
	  yLocation=(yLocation+1)%size;
		return new Point(xLocation, yLocation);
	}
	
	public Point moveEast() {
    xLocation=(xLocation+1)%size;
    return new Point(xLocation, yLocation);
	}
	
	public Point moveSouth() {
    yLocation=(yLocation-1+size)%size;
    return new Point(xLocation, yLocation);
	}
	
	public Point moveWest() {
    xLocation=(xLocation-1+size)%size;
    return new Point(xLocation, yLocation);
	}
	
	public boolean isHasGold() {
		return hasGold;
	}

	public void setHasGold(boolean hasGold) {
		this.hasGold = hasGold;
	}

	public int getX() {
	  return xLocation;
	}
	
	public int getY() {
	  return yLocation;
	}
	
	//mark cell is Known: exit true, other false
	public void findExit(Point exitPoint) {
	  knowsExitLocation = true;
		agentWorld.agentWorld[exitPoint.getX()][exitPoint.getY()].putExit();
	}
}
